﻿using System;
using System.Collections.Generic;
using PropertyExpression.Common;
using PropertyExpression.ControllableQuery;

namespace PropertyExpression.ControllableQueryTool
{
    public class CheckQueryContext
    {
        private int sqlParameterIndex;
        private readonly List<ParamInfo> paramInfoList;

        internal CheckQueryContext(List<ParamInfo> paramInfoList)
        {
            this.paramInfoList = paramInfoList;
        }

        public IParam<string> CreateStringParam()
        {
            return new Param<string>(this);
        }

        public IParam<Guid> CreateGuidParam()
        {
            return new Param<Guid>(this);
        }

        private class Param<T> : IParam<T>
        {
            private readonly CheckQueryContext parent;

            public Param(CheckQueryContext parent)
            {
                this.parent = parent;
            }

            public ISqlParam<T> GenerateSqlParam()
            {
                return new SqlParam(this, parent.GetNextSqlParameterName());
            }

            private class SqlParam : ISqlParam<T>
            {
                private readonly Param<T> parent;
                private readonly string parameterName;

                public SqlParam(Param<T> parent, string parameterName)
                {
                    this.parent = parent;
                    this.parameterName = parameterName;
                }

                public string ToSql()
                {
                    var sqlParameterName = string.Format("@{0}", parameterName);
                    parent.parent.paramInfoList.Add(
                        new ParamInfo(
                            sqlParameterName,
                            delegate { return OptionalValue.Nothing<string>(); },
                            (paramInfo, xmlDocument, xmlNamespaceManager) =>
                            xmlDocument.SelectSingleNode(
                                string.Format(
                                    @"//a:ColumnReference[@Column='{0}']/ancestor::a:Convert/@DataType",
                                    paramInfo.Name),
                                xmlNamespaceManager).InnerText,
                            typeof(T)
                            )
                        );
                    //TODO: избавиться от копипаста: добавление @ идет и в алгоритме выполнения запроса
                    return string.Format(@"
{0}
",
                                         sqlParameterName);
                }

                public override string ToString()
                {
                    return ToSql();
                }
            }

            public override string ToString()
            {
                return this.ToSql();
            }
        }

        private string GetNextSqlParameterName()
        {
            //TODO: избавиться от копипаста: см. QueryContext
            var result = string.Format("p{0}", sqlParameterIndex);
            sqlParameterIndex++;
            return result;
        }
    }
}